home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Expert
/
Windows Expert.iso
/
windownt
/
uupc11yt.zip
/
RNEWS
/
HISTORY.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-13
|
14KB
|
423 lines
/*--------------------------------------------------------------------*/
/* h i s t o r y . c */
/* */
/* News history file maintenance for UUPC/extended. */
/* */
/* Written by Mike Lipsie */
/* */
/* The history file */
/* */
/* This file describes and implements the history file. */
/* */
/* The history file is [newsdir]/history and is "added" to by */
/* rnews. It is "pruned" by expire and is used by rnews (to */
/* check that the article has not arrived before), expire (to */
/* find all copies of the article), and rn (to mark as read all */
/* copies of an article.) */
/* */
/* The history file is entirely ASCII. */
/* */
/* The first line is a code that identifies the version level */
/* (so that future versions can automatically upgrade.) For */
/* version one that code is "ZIP1". */
/* */
/* Every line (except the version line) is the record of a */
/* single incoming article. That line is exactly as described */
/* without added spaces or other punctuation. The first field */
/* is the Message-ID including (or added if they don't exist), */
/* the "<" and ">", a space, the date received (dd/mm/yyyy with */
/* days and months being zero filled if necessary), a space, */
/* and the "destination" information. */
/* */
/* The destination information is the Newsgroups: with a colon */
/* and the article number for each group added (article number */
/* zero is used for newsgroups not accepted.) */
/* */
/* For example, if article <123@pyramid> was received on 3 Jan */
/* 1992 and was posted to ba.food, ba.transportation, and */
/* soc.singles and ended up in article 4334, 1234, and 56789 */
/* (respectively), the record would be */
/* */
/* <123@pyramid> 03/01/1992 */
/* ba.food:4334,ba.transportation:1234,soc.singles:56789 */
/* */
/* To speed access into the history file there is a parallel */
/* file history.ndx which contains information where each day's */
/* worth of history records begins. The first line is a */
/* version number and must be the same as that of the history */
/* file. All the other records are the 10 character date code, */
/* a space, and a ten digit location code (right justified, */
/* zero or blank filled.) The location code is the byte */
/* displacement into the history file of the first record with */
/* that date code. */
/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*/
/* System include files */
/*--------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
/*--------------------------------------------------------------------*/
/* UUPC/extended include files */
/*--------------------------------------------------------------------*/
#include "lib.h"
#include "hlib.h"
#include "timestmp.h"
#include "active.h"
#include "history.h"
/* These variables are used to improve the performance of checking
* for previous existance of an article.
*
* The basic theory of how this feature works is that a file
* (history.dbm) is built with enough information (it is hoped)
* to eliminate 99% (well, most) of the non matching message IDs.
* A check is made when a match is made confiming that the match
* is real. Since most articles are not "re-sends" (all if you
* have only one feed) this won't impose a large overhead.
*
* The information that is used to eliminate unnecessary checks into
* the history file for duplicate messageIDs is the first ten
* characters of the message ID (not including the leading "<"),
* the number of characters in the full ID (including the "<" and ">"),
* a checksum of the full ID (also including the "<" and ">"), and
* the location in the history file of the full ID.
*
* Additionally, an array of MAXbuf (currently 8) buffers of history.dbm
* are maintained in memory to avoid disk I/O.
*
*/
int cur_buff = 0;
int cur_off = 0;
#define MAXbuf 8
char *hb[MAXbuf];
int hb_blk[MAXbuf];
extern FILE *hfile;
FILE *hdbm_file = NULL;
struct perf_elem {
char IDpart[10]; /* The first 10 characters (after the "<") of the message-ID */
char cksum; /* Checksum of the entire ID (including <>) */
char IDlen; /* Number of characters in the ID (including <>) */
long where; /* ftell() in file of actual record */
};
/*--------------------------------------------------------------------*/
/* h i s t o r y _ e x i s t s */
/* */
/* Determine if the history file exists and is a file (instead */
/* of a directory). */
/*--------------------------------------------------------------------*/
boolean history_exists( void )
{
char hfile_name[FILENAME_MAX];
struct stat buff;
mkfilename(hfile_name, E_newsdir, "history");
if ((stat(hfile_name, &buff) == 0) && buff.st_mode & S_IFREG)
return TRUE;
else
return FALSE;
} /* history_exists */
/*--------------------------------------------------------------------*/
/* o p e n _ h i s t o r y */
/* */
/* Open the history file and verify that it is of the correct */
/* version. If any error occurs, NULL is returned. */
/*--------------------------------------------------------------------*/
#ifdef __TURBOC__
#pragma argsused
#endif
FILE *open_history(char *history_date)
{
#ifdef NEXT_RELEASE_MAYBE
char hfile_name[FILENAME_MAX];
FILE *hfile;
FILE *index_file;
char buff[BUFSIZ];
mkfilename(hfile_name, newsdir, "history");
hfile = fopen(hfile_name, "a+b");
if (hfile == NULL) {
printmsg(0,"Unable to open history file");
return hfile;
}
fseek(hfile, 0L, SEEK_SET);
fgets(buff, sizeof(buff), hfile);
buff[strlen(buff)-1] = '\0';
if (buff[strlen(buff)-1] == '\r') buff[strlen(buff)-1] = '\0';
if ((strlen(buff)) != strlen(H_VERSION)) {
printmsg(0, "History version incorrect");
return NULL;
}
if (!equal(buff, H_VERSION)) {
printmsg(0, "History version incorrect");
return NULL;
}
fseek(hfile, 0L, SEEK_END); /* I know it is unnecessary */
/* Now the index file */
strcat(hfile_name, ".ndx");
index_file = fopen(hfile_name, "a+b");
if (index_file == NULL) {
printmsg(0,"Unable to open history file index");
}
fseek(index_file, 0L, SEEK_SET);
fgets(buff, sizeof(buff), index_file);
buff[strlen(buff)-1] = '\0';
if (buff[strlen(buff)-1] == '\r') buff[strlen(buff)-1] = '\0';
if ((strlen(buff)) != strlen(H_VERSION)) {
printmsg(0, "History index version incorrect");
}
if (!equal(buff, H_VERSION)) {
printmsg(0, "History index version incorrect");
}
fseek(index_file, -21L, SEEK_END);
fgets(buff, 25, index_file);
if (strncmp(history_date, buff, strlen(history_date)) != 0) {
fseek(index_file, 0L, SEEK_END);
sprintf(buff, "%s %9.9ld\n", history_date, ftell(hfile));
fwrite(buff, sizeof(char), strlen(buff), index_file);
}
fclose(index_file);
#else
hfile = NULL;
#endif
return NULL;
}
/*
Create a history file.
*/
FILE *create_history(char *history_date) {
char hfile_name[FILENAME_MAX];
FILE *hfile;
FILE *index_file;
char buff[BUFSIZ];
mkfilename(hfile_name, E_newsdir, "history");
hfile = fopen(hfile_name, "wb");
if (hfile == NULL) {
printmsg(0, "Unable to create history file");
return hfile;
}
strcpy(buff, H_VERSION);
strcat(buff, "\n");
fwrite(buff, sizeof(char), strlen(buff), hfile);
strcat(hfile_name, ".ndx");
index_file = fopen(hfile_name, "wb");
fwrite(buff, sizeof(char), strlen(buff), index_file);
sprintf(buff, "%s %9.9ld\n", history_date, ftell(hfile));
fwrite(buff, sizeof(char), strlen(buff), index_file);
fclose(index_file);
return hfile;
}
void init_history_dbm(void) {
#ifdef NEXT_RELEASE_MAYBE
int not_eof;
char *t;
long l;
int i;
int j;
int cur_block;
struct perf_elem *p;
char dbm_name[FILENAME_MAX];
char hbuf[BUFSIZ]; /* Buffer for each history file record */
mkfilename(dbm_name, tempdir, "history.dbm");
hdbm_file = fopen(dbm_name, "w+b");
if (hdbm_file == NULL) {
printmsg(0,"Unable to create history dbm file");
exit(5);
}
for (i = 0; i < MAXbuf; i++) {
hb[i] = malloc(BUFSIZ);
checkref(hb[i]);
hb_blk[i] = -1;
}
cur_block = 0;
cur_buff = 0;
cur_off = 0;
/* Now build the file */
fseek(hfile, (long)(strlen(H_VERSION)+1), SEEK_SET); /* Back to the beginning */
not_eof = TRUE;
while (not_eof) {
l = ftell(hfile);
t = fgets(hbuf, BUFSIZ, hfile);
if (t == NULL) {
not_eof = FALSE;
} else {
if (cur_off >= (BUFSIZ/sizeof(struct perf_elem))) {
fwrite(hb[cur_buff], sizeof(char), BUFSIZ, hdbm_file);
hb_blk[cur_buff] = cur_block++;
cur_off = 0;
if (++cur_buff >= MAXbuf) {
cur_buff = 0;
}
}
p = (struct perf_elem *)hb[cur_buff];
p += cur_off++;
t = strchr(hbuf, ' ');
if (t == NULL) t = hbuf;
*t = '\0';
p->where = l;
p->IDlen = strlen(t);
j = 0;
for (i = p->IDlen-1; i >= 0; i--) {
j = j + t[i];
}
p->cksum = (char)j;
strncpy(p->IDpart, &(t[1]), sizeof(p->IDpart));
}
} /* while not eof */
/* Dump out last (probably partial) block */
if (cur_off < (BUFSIZ/sizeof(struct perf_elem))) {
p = (struct perf_elem *)hb[cur_buff];
p += cur_off;
strnset((char *)p, '\0', (&hb[cur_buff][BUFSIZ] - &(char *)p));
}
fwrite(hb[cur_buff], sizeof(char), BUFSIZ, hdbm_file);
hb_blk[cur_buff] = cur_block;
#endif
return;
}
/*--------------------------------------------------------------------*/
/* i s _ i n _ h i s t o r y */
/* */
/* Check whether messageID is already in the history file. */
/*--------------------------------------------------------------------*/
boolean is_in_history(FILE *hfile, char *messageID)
{
#ifdef NEXT_RELEASE_MAYBE
int this_blk;
struct perf_elem *p;
if (hdbm_file == NULL) {
/* Initialize */
init_history_dbm();
}
/* First check the blocks in memory */
this_blk = 0;
cur_off = 0;
while (this_blk < MAXbuf) {
if (cur_off >= (BUFSIZ/sizeof(struct perf_elem))) {
cur_off = 0;
if (++this_blk >= MAXbuf) {
break;
}
if (hb_blk[this_blk] == -1) break;
}
p = (struct perf_elem *)hb[this_blk];
p += cur_off++;
if (check_out_this_one(messageID, p)) {
return TRUE;
}
}
/* Now check out the rest of the file */
#else
/*--------------------------------------------------------------------*/
/* Slow but true version extracted from rnews.c by ahd */
/*--------------------------------------------------------------------*/
boolean not_eof = TRUE;
fseek(hfile, (long)(strlen(H_VERSION)+1), SEEK_SET);
/* Back to the beginning */
/*--------------------------------------------------------------------*/
/* Scan the entire disk file from the beginning */
/*--------------------------------------------------------------------*/
while (not_eof)
{
char hist_record[BUFSIZ];
char *gc_ptr = fgets(hist_record, sizeof(hist_record), hfile);
if (gc_ptr == NULL)
not_eof = FALSE;
else {
gc_ptr = strchr(hist_record, ' ');
if (gc_ptr == NULL)
gc_ptr = hist_record;
*gc_ptr = '\0';
printmsg(9, "rnews:Comparing to history:%s", hist_record);
if (equal(hist_record, messageID))
return TRUE;
} /* else */
} /* while (not_eof) */
#endif
return FALSE;
} /* is_in_history */
#ifdef NEXT_RELEASE_MAYBE
int check_out_this_one(char *m_id, struct perf_elem *p)
{
printf("check_out_this_one called \n");
return TRUE;
}
#endif